﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using FMSpaceShooter.Screens;
using FMSpaceShooter.GameObjects;


namespace FMSpaceShooter.GameData
{
    class Collider
    {
        GameplayScreen screen;
        public Collider(GameplayScreen screen)
        {
            this.screen = screen;
        }

        public void Update(GameTime gameTime)
        {
            //var bullets = screen.GOM.GameObjects.Where(go => typeof(BulletBase).IsAssignableFrom(go.GetType()));

            var damagers = screen.GOM.GameObjects.Where(go => go.CanDamageEnemy && go.DoesCollide);
            var enemies = screen.GOM.GameObjects.Where(go => !go.IsFriendly && go.DoesCollide);
            var items = screen.GOM.GameObjects.Where(go => go.isItem && go.DoesCollide);

            foreach (var enemy in enemies)
            {
                foreach (var damager in damagers)
                {
                    if (IsCollided(damager, enemy, gameTime))
                    {
                        enemy.Hit(damager.Damage);
                        damager.Hit(enemy.Damage);
                    }
                }
                if (!screen.GOM.PlayerOne.IsInvulnerable && IsCollided(enemy, screen.GOM.PlayerOne, gameTime))
                {
                    screen.GOM.PlayerOne.Hit(enemy.Damage);
                    if (!enemy.isBoss)
                    {
                        enemy.Die();
                    }
                }
            }

            foreach (var item in items)
            {
                if (IsCollided(item, screen.GOM.PlayerOne, gameTime))
                {
                    item.Hit(0);
                }
            }
        }

        public static bool IsCollided(ObjectBase first, ObjectBase second, GameTime gt)
        {
            var distance = Vector2.Distance(first.Position, second.Position);
            if (distance - (first.Radius + second.Radius) < 0)
            {
                var firstTrans = first.GetTransforms();
                return IntersectPixels(firstTrans, (int)first.TextureSize.X, (int)first.TextureSize.Y, first.TextureData,
                     second.GetTransforms(), (int)second.TextureSize.X, (int)second.TextureSize.Y, second.TextureData);
            }
            return false;
        }

        public static bool IntersectPixels(
                            Matrix transformA, int widthA, int heightA, Color[] dataA,
                            Matrix transformB, int widthB, int heightB, Color[] dataB)
        {
            // Calculate a matrix which transforms from A's local space into
            // world space and then into B's local space
            Matrix transformAToB = transformA * Matrix.Invert(transformB);

            // When a point moves in A's local space, it moves in B's local space with a
            // fixed direction and distance proportional to the movement in A.
            // This algorithm steps through A one pixel at a time along A's X and Y axes
            // Calculate the analogous steps in B:
            Vector2 stepX = Vector2.TransformNormal(Vector2.UnitX, transformAToB);
            Vector2 stepY = Vector2.TransformNormal(Vector2.UnitY, transformAToB);

            // Calculate the top left corner of A in B's local space
            // This variable will be reused to keep track of the start of each row
            Vector2 yPosInB = Vector2.Transform(Vector2.Zero, transformAToB);

            // For each row of pixels in A
            for (int yA = 0; yA < heightA; yA++)
            {
                // Start at the beginning of the row
                Vector2 posInB = yPosInB;

                // For each pixel in this row
                for (int xA = 0; xA < widthA; xA++)
                {
                    // Round to the nearest pixel
                    int xB = (int)Math.Round(posInB.X);
                    int yB = (int)Math.Round(posInB.Y);

                    // If the pixel lies within the bounds of B
                    if (0 <= xB && xB < widthB &&
                        0 <= yB && yB < heightB)
                    {
                        // Get the colors of the overlapping pixels
                        Color colorA = dataA[xA + yA * widthA];
                        Color colorB = dataB[xB + yB * widthB];

                        // If both pixels are not completely transparent,
                        if (colorA.A != 0 && colorB.A != 0)
                        {
                            // then an intersection has been found
                            return true;
                        }
                    }

                    // Move to the next pixel in the row
                    posInB += stepX;
                }

                // Move to the next row
                yPosInB += stepY;
            }

            // No intersection found
            return false;
        }

        //private static bool CompletePixelCompare(ObjectBase first, ObjectBase second, GameTime gt)
        //{
        //    var firstRT = first.DrawSolid(gt);
        //    var secondRT = second.DrawSolid(gt);

        //    int totalPixels = firstRT.Width * firstRT.Height;

        //    Color[] firstPixels = new Color[totalPixels];
        //    firstRT.GetData<Color>(firstPixels);

        //    Color[] secondPixels = new Color[totalPixels];
        //    secondRT.GetData<Color>(firstPixels);

        //    for (int i = 0; i < totalPixels; i++)
        //    {
        //        if (firstPixels[i].A != 0)
        //        {
        //            if (secondPixels[i].A != 0)
        //            {
        //                return true;
        //            }
        //        }
        //    }
        //    return false;
        //}
    }
}
